Imports System.IO
Imports System.Reflection
Imports System.Xml.Serialization

Public Class WindowsFilePreferencesNode : Inherits AbstractPreferencesNode

    Private Shared mFileSystemRootNode As IPreferencesNode
    'Private Shared mFileUserRootNode As IPreferencesNode

    Private Shared mAppSystemRootDirectory As String
    'Private Shared mAppUserRootDirectory As String

    'Private Shared mAppSpecificDirectoryName As String

    Shared Sub New()
        'TODO: Add Isolator class
        'mAppSpecificDirectoryName = "Preferences\" & _
        '    Isolator.GetDomainIdentity(AppDomain.CurrentDomain) & Path.DirectorySeparatorChar & _
        '    Isolator.GetAssemblyIdentity(Isolator.GetNearestCallingAssembly())

        'mAppSystemRootDirectory = 
        '	Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + 
        '	Path.DirectorySeparatorChar + appSpecificDirectoryName;

        mAppSystemRootDirectory = AppDomain.CurrentDomain.BaseDirectory & "Preferences"
        'mAppUserRootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & Path.DirectorySeparatorChar & mAppSpecificDirectoryName
        mFileSystemRootNode = New WindowsFilePreferencesNode(Nothing, String.Empty, True)
        'mFileUserRootNode = New WindowsFilePreferencesNode(Nothing, String.Empty, False)
    End Sub

    Friend Shared ReadOnly Property WindowsFileSystemRootNode() As IPreferencesNode
        Get
            Return mFileSystemRootNode
        End Get
    End Property

    Friend Shared ReadOnly Property WindowsFileUserRootNode() As IPreferencesNode
        Get
            'TODO: mFileUserRootNode replace to mFileSystemRootNode
            Return mFileSystemRootNode
        End Get
    End Property

    Private ReadOnly mFileSystemRepresentative As DirectoryInfo

    ''' <summary>
    ''' Set the parent, the name, and the appName. App name is the application that
    ''' uses this library's name. This application name is used so that applications
    ''' don't trample one another's user preferences in user's Application Data 
    ''' directory.
    ''' </summary>
    ''' <param name="parent">The parent node of this node.</param>
    ''' <param name="name">The name of this node.</param>
    ''' <param name="appName">The name of the application calling this library.</param>
    Friend Sub New(ByVal parent As AbstractPreferencesNode, ByVal name As String, ByVal isSystemNode As Boolean)
        MyBase.New(parent, name, isSystemNode)
        ' the absolute path has already been calculated in base,
        ' so let's just use that.
        Try
            If isSystemNode Then
                mFileSystemRepresentative = Directory.CreateDirectory(mAppSystemRootDirectory & AbsolutePath.Replace(AbstractPreferencesNode.PathSeparatorChar, Path.DirectorySeparatorChar))
            Else
                ' TODO: mAppSystemRootDirectory replace to mAppUserRootDirectory
                mFileSystemRepresentative = Directory.CreateDirectory(mAppSystemRootDirectory & AbsolutePath.Replace(AbstractPreferencesNode.PathSeparatorChar, Path.DirectorySeparatorChar))
            End If
        Catch ex As Exception
            'TODO: Load string from resource
            Throw New PreferencesStorageException("Exception raised while creating FileUserPreferencesNode", ex)
        End Try
    End Sub

    Protected Overrides Function StorageGetChildNodeForPath(ByVal childNodeName As String) As IPreferencesNode
        Return New WindowsFilePreferencesNode(Me, childNodeName, IsSystemNode)
    End Function

    Protected Overrides Sub StorageSynchronize()
    End Sub

    Protected Overrides Function StorageGetBinary(ByVal key As String) As Byte()
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName & Path.DirectorySeparatorChar & key)
        If Not aFileInfo.Exists Then
            Return Nothing
        Else
            Dim streamFromKey As Stream = aFileInfo.OpenRead()
            Dim binReader As BinaryReader = New BinaryReader(streamFromKey)

            Dim contents(aFileInfo.Length - 1) As Byte
            binReader.Read(contents, 0, aFileInfo.Length)
            binReader.Close()
            Return contents
        End If
    End Function

    Protected Overrides Function StorageGetSerializedObject(ByVal key As String, ByVal serializer As XmlSerializer) As Object
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName & Path.DirectorySeparatorChar & key)
        If Not aFileInfo.Exists Then
            Return Nothing
        Else
            Dim streamFromKey As Stream = aFileInfo.OpenRead()
            'IFormatter formatter = new BinaryFormatter();
            'object deserializedObject = formatter.Deserialize(streamFromKey);
            Dim deserializedObject As Object = serializer.Deserialize(streamFromKey)
            streamFromKey.Close()
            Return deserializedObject
        End If
    End Function

    Protected Overrides Function StorageGetText(ByVal key As String) As String
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName + Path.DirectorySeparatorChar + key)
        If Not aFileInfo.Exists Then
            Return Nothing
        Else
            Dim streamFromKey As Stream = aFileInfo.OpenRead()
            Dim textReader As textReader = New StreamReader(streamFromKey)
            Dim text As String = textReader.ReadToEnd()
            textReader.Close()
            Return text
        End If
    End Function

    Protected Overrides Function StorageKeys() As String()
        Dim files As FileInfo() = mFileSystemRepresentative.GetFiles()
        Dim fileNames(files.Length - 1) As String
        For i As Integer = 0 To fileNames.Length - 1
            fileNames(i) = files(i).Name
        Next
        Return fileNames
    End Function

    Protected Overrides Sub StoragePutBinary(ByVal key As String, ByVal val As Byte())
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName & Path.DirectorySeparatorChar & key)
        Dim streamToKey As Stream = aFileInfo.Open(FileMode.Create)
        Dim binWriter As BinaryWriter = New BinaryWriter(streamToKey)
        binWriter.Write(val)
        binWriter.Close()
    End Sub

    Protected Overrides Sub StoragePutSerializableObject(ByVal key As String, ByVal val As Object)
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName & Path.DirectorySeparatorChar & key)
        Dim streamToKey As Stream = aFileInfo.Open(FileMode.Create)
        'IFormatter formatter = new BinaryFormatter();
        'formatter.Serialize(streamToKey, val);
        Dim serializer As XmlSerializer = New XmlSerializer(val.GetType())
        serializer.Serialize(streamToKey, val)
        streamToKey.Close()
    End Sub

    Protected Overrides Sub StoragePutText(ByVal key As String, ByVal val As String)
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName & Path.DirectorySeparatorChar & key)
        Dim textWriter As textWriter = aFileInfo.CreateText()
        textWriter.Write(val)
        textWriter.Close()
    End Sub

    Protected Overrides Sub StorageRemoveAllPreferencesFromNode()
        Dim files As FileInfo() = mFileSystemRepresentative.GetFiles()
        For Each aFileInfo As FileInfo In files
            aFileInfo.Delete()
        Next
    End Sub

    Protected Overrides Sub StorageRemoveNode()
        ' remove everything from this directory, ahem
        ' including itself.
        mFileSystemRepresentative.Delete(True)
    End Sub

    Protected Overrides Function StorageRemovePreferenceFromNode(ByVal key As String) As Boolean
        Dim aFileInfo As FileInfo = New FileInfo(mFileSystemRepresentative.FullName & Path.DirectorySeparatorChar & key)
        If Not aFileInfo.Exists Then
            Return False
        Else
            aFileInfo.Delete()
            Return True
        End If
    End Function


End Class
